package py.edu.ucsa.sisale.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import py.edu.ucsa.sisale.config.Configuration;
import py.edu.ucsa.sisale.config.ConfigurationFactory;


public abstract class ServiceHelper extends ServiceConfig implements Serializable
{
	private static final long serialVersionUID = -1248409054376072544L;

    private static final Logger log = LoggerFactory.getLogger(ServiceHelper.class);
    
    protected static final String projectURI = "/sisalews";
    
    protected final Configuration config = ConfigurationFactory.getConfig();
    
    protected HttpClient httpClient = null;
    protected HttpPost httpPost = null;
    protected HttpPut httpPut = null;
    protected HttpGet httpGet = null;
    protected HttpDelete httpDelete= null;
    
    private String errorMessage = null;
    
    protected void createGetRequest(String uri)
    {
        httpClient = HttpClientBuilder.create().build();
        System.out.println("URI FORMADO - " + config + "-" + uri);
        httpGet = new HttpGet(AppHelper.buildUrl(config.getRestServiceHost(), uri));
    }

    protected void createPostRequest(String uri)
    {
        httpClient = HttpClientBuilder.create().build();
        httpPost = new HttpPost(AppHelper.buildUrl(config.getRestServiceHost(), uri));
    }
    
    protected void createPutRequest(String uri)
    {
        httpClient = HttpClientBuilder.create().build();
        httpPut = new HttpPut(AppHelper.buildUrl(config.getRestServiceHost(), uri));
    }
    
    protected void createDeleteRequest(String uri)
    {
        httpClient = HttpClientBuilder.create().build();
        httpDelete = new HttpDelete(AppHelper.buildUrl(config.getRestServiceHost(), uri));
    }

    protected boolean isResponseHasErrors(HttpResponse response)
    {
        int statusCode = response.getStatusLine().getStatusCode();
        
        if(statusCode >= 300 && statusCode < 600)
        {
            String errorCode = String.valueOf(statusCode);
            
//            if(bundle.containsKey(errorCode))
//            {
//                errorMessage = bundle.getString(errorCode);
//            }
//            else
//            {
//                errorMessage = bundle.getString("py.edu.ucsa.sisale.error.unknown");
//            }
            
            return true;
        }
        
        //--
//        if(statusCode < ErrorCode.values().length)//TODO test!
//        {
//            errorMessage = bundle.getString("py.edu.ucsa.sisale.error.DATA_ACCESS_EXCEPTION");
//        }
        
        return false; 
    }
     
    protected HttpResponse getGetResponse() throws ClientProtocolException, IOException
    {
    	this.setAuthorizationHeader(httpGet);
        return httpClient.execute(httpGet);
    }

    protected HttpResponse getPostResponse() throws ClientProtocolException, IOException
    {
    	this.setAuthorizationHeader(httpPost);
        return httpClient.execute(httpPost);
    }
    
    protected HttpResponse getPutResponse() throws ClientProtocolException, IOException
    {
    	this.setAuthorizationHeader(httpPut);
        return httpClient.execute(httpPut);
    }
    
    protected HttpResponse getDeleteResponse() throws ClientProtocolException, IOException
    {
    	this.setAuthorizationHeader(httpDelete);
        return httpClient.execute(httpDelete);
    }

    
    protected String getJSONData(HttpResponse response) throws IllegalStateException, IOException
    {
//        String charset = response.getParams().getParameter("http.protocol.content-charset").toString();
        
        InputStream inputStream = response.getEntity().getContent();
        
        return IOUtils.toString(inputStream, "utf-8");
    }

    /**
     * <p>set the JSONData in the httpPost call</p> 
     * 
     * @param jsondata
     * @throws UnsupportedEncodingException
     */
    protected void setEntity(String jsondata) throws UnsupportedEncodingException
    {
        httpPost.setEntity(new StringEntity(jsondata));        
    }
    
    protected void setEntityPut(String jsondata) throws UnsupportedEncodingException
    {
        httpPut.setEntity(new StringEntity(jsondata));        
    }

    /**
     * finds and entity with the given value, looking the REST service with the given URI
     * 
     * @param uri
     * @param value
     * @return JSONData
     * @throws Exception 
     */
    protected String find(String uri, Object value) throws Exception
    {
        createGetRequest(uri+"/"+ value);
        //createGetRequest(uri);
        
        HttpResponse response = getGetResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    protected String findTwo(String uri) throws Exception
    {        
        createGetRequest(uri);
        
        HttpResponse response = getGetResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    /**
     * 
     * @param uri
     * @param value
     * @return
     * @throws Exception
     */
    protected String findWithTwoParam(String uri, Object value1, Object value2) throws Exception
    {
        createGetRequest(uri+"/"+ value1+"-"+value2);
        //createGetRequest(uri);
        
        HttpResponse response = getGetResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }

    /**
     * 
     * @param uri
     * @param dominio
     * @param abreviatura
     * @return
     * @throws Exception
     */
    protected String find(String uri, String dominio, String abreviatura) throws Exception
    {
        createGetRequest(uri+"/"+ dominio+"/"+abreviatura);
        
        HttpResponse response = getGetResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    /**
     * filtered search in the given URI<br>
     * <b>previously the setEntity(String jsondata) had to be set<b>
     *  
     * @param uri
     * @param jsondata 
     * @return
     * @throws Exception
     */
    protected String filter(String uri, String jsondata) throws Exception
    {
        createPostRequest(uri);
        setEntity(jsondata);
        
        HttpResponse response = getPostResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpPost.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
        

    protected String list(String uri) throws Exception
    {
        createGetRequest(uri);
        
        HttpResponse response = getGetResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }

    protected String list(String uri, Object parametro) throws Exception{
        createGetRequest(uri+"/"+ parametro);
        
        HttpResponse response = getGetResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }

    protected String list(String uri, Object valor, int posicionInicial, int maxResult) throws Exception{
        createGetRequest(uri + "/" + valor + "/" + posicionInicial + "/" + maxResult);
        
        HttpResponse response = getGetResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    protected String list(String uri, Object valor1, Object valor2, int posicionInicial, int maxResult) throws Exception{
        createGetRequest(uri + "/" + valor1 + "/" + valor2 + "/" + posicionInicial + "/" + maxResult);
        
        HttpResponse response = getGetResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    protected String list(String uri, Object valor1, Object valor2, Object valor3, int posicionInicial, int maxResult) throws Exception{
        createGetRequest(uri + "/" + valor1 + "/" + valor2 + "/" + valor3 + "/" + posicionInicial + "/" + maxResult);
        
        HttpResponse response = getGetResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    protected String list(String uri, Object valor1, Object valor2, Object valor3, Object valor4, int posicionInicial, int maxResult) throws Exception{
        createGetRequest(uri + "/" + valor1 + "/" + valor2 + "/" + valor3 + "/" + valor4 + "/" + posicionInicial + "/" + maxResult);
        
        HttpResponse response = getGetResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    protected String list(String uri, long arg1, long arg2) throws Exception{
        createGetRequest(uri + "/" + arg1 + "/" + arg2);
        
        HttpResponse response = getGetResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    protected String list(String uri, long arg1, long arg2, long arg3) throws Exception{
        createGetRequest(uri + "/" + arg1 + "/" + arg2 + "/" + arg3);
        
        HttpResponse response = getGetResponse();
        
        if(isResponseHasErrors(response)) 
        {
            log.error(httpGet.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    /**
     * persists or updates the given entity in JSONData format<b>
     * with the given REST service URI
     * 
     * @param uri
     * @param jsondata
     * @return
     * @throws Exception
     */
    protected String createOrUpdate(String uri, String jsondata) throws Exception
    {
    	System.out.println("URI " + uri + " jsondata " + jsondata);
        createPostRequest(uri);
        setEntity(jsondata);
        
        HttpResponse response = getPostResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpPost.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }
    
    protected String update(String uri, String jsondata) throws Exception
    {
        createPutRequest(uri);
        setEntityPut(jsondata);
        
        HttpResponse response = getPutResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpPost.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        
        return getJSONData(response);
    }

    /**
     * @param uri
     * @param id
     * @throws Exception
     */
    protected String executePost(String uri, Long id) throws Exception
    {
        createPostRequest(uri+"/"+id);

        HttpResponse response = getPostResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpPost.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        return getJSONData(response);
    }

    /**
     * deletes a record with the given ID<b>
     * and the given REST service URI 
     * 
     * @param uri
     * @param id
     * @throws Exception
     */
    protected String delete(String uri, Long id) throws Exception
    {
        createDeleteRequest(uri+"/"+id);

        HttpResponse response = getDeleteResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpDelete.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        return getJSONData(response);
    }
    
    protected String deleteParams(String uri, String id) throws Exception
    {
        createDeleteRequest(uri+"/"+id);

        HttpResponse response = getDeleteResponse();

        if(isResponseHasErrors(response)) 
        {
            log.error(httpDelete.getURI().toString());
            log.error(response.getStatusLine().toString());
            
            throw new Exception(); 
        }
        return getJSONData(response);
    }
    
    public String getErrorMessage()
    {
        return errorMessage;
    }
    
    
    
    protected void closeConnection()
    {
        httpClient.getConnectionManager().shutdown();
    }

}
